package nc.impl.hrpbm.deptbuget;

import nc.bs.dao.BaseDAO;
import nc.bs.hrpbm.deptbudget.DeptBudgetExpenditureDetailService;
import nc.jdbc.framework.processor.MapListProcessor;
import nc.pub.hrpbm.util.HrpbmReportUtils;
import nc.pub.smart.context.SmartContext;
import nc.pub.smart.data.DataSet;
import nc.pub.smart.metadata.Field;
import nc.pub.smart.metadata.MetaData;
import nc.vo.pub.BusinessException;
import nc.vo.pubapp.pattern.exception.ExceptionUtils;
import nccloud.commons.lang.ArrayUtils;
import org.apache.commons.collections4.CollectionUtils;
import uap.lfw.bq.portal.base.StringUtils;

import java.math.BigDecimal;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class DeptBudgetExpenditureDetailServiceImpl implements DeptBudgetExpenditureDetailService {
    HrpbmReportUtils Utils = new HrpbmReportUtils();
    private BaseDAO baseDAO;

    public BaseDAO getBaseDAO() {
        return baseDAO == null ? new BaseDAO() : baseDAO;
    }

    public static final String cwbudgetdeptcode = "405"; // 财务部门编码
    public static final String firstparentcode = "1"; // 收支项目: 收入科目编码

    String[] fields = new String[]{"inoutbusiclassname", "deptname", "nyear", "f1project_name", "f2project_name",
            "type_name", "amount_01", "amount_02", "amount_03", "amount_04", "amount_05",
            "amount", "inoutbusiclasscode", "fundsourceamount"};
    String[] fieldCaptions = new String[]{"收支科目", "部门名称", "年度", "一级项目名称", "二级项目名称",
            "项目分类", "财政基本拨款经费", "财政项目拨款经费", "科教经费", "非同级财政拨款经费", "其他经费",
            "合计", "科目编码", "来源合计"};

    @Override
    public DataSet process(SmartContext context) throws BusinessException {

        MetaData metadata = this.initMetaData();
        Utils.handelContext(context);
        List<Map<String, Object>> sqlResult = getBusinessData(context);

        return buildDataSetobj(metadata, sqlResult, fields);
    }


    private List getBusinessData(SmartContext context) throws BusinessException {

        String pk_org = (String) context.getAttribute("pk_org");
        String budgetdept = (String) context.getAttribute("pk_budgetdept");
        String pk_inoutclass = (String) context.getAttribute("pk_inoutclass");
        String nyear = (String) context.getAttribute("nyear") == null ? "2025" : (String) context.getAttribute("nyear");
        String isfund = (String) context.getAttribute("isfund");
        String f1project = (String) context.getAttribute("f1project");
        String f2project = (String) context.getAttribute("f2project");
//		String inoutlevel = (String) context.getAttribute("level");

        StringBuffer sql = new StringBuffer();
        sql.append("SELECT hbd.name AS deptname,");//
        sql.append("       hbrd.nyear AS nyear,");//
        sql.append("       ee.pk_inoutbusiclass AS pk_inoutclass,");//
        sql.append("       ee.code as inoutbusiclasscode,");//
        sql.append("       ee.name as inoutbusiclassname,");//
        sql.append("       fip_docview_b.sfzjcode AS sfzjcode,");//
        sql.append("       bf.code as fundsourcecode,");//
        sql.append("       bf.name as fundsourcename,");//
        sql.append("       projectclass.eps_name AS type_name,");//
        sql.append("       project.project_name AS f1project_name,");//
        sql.append("       project2.project_name AS f2project_name,");//
        sql.append("       project.pk_project AS pk_f1project,");//
        sql.append("       project2.pk_project AS pk_f2project,");//
        sql.append("       CASE");//
        sql.append("         WHEN hbr.approvestatus = '1' THEN");//
        sql.append("          nvl(hbrd.amount_firstdown, 0)");//
        sql.append("         ELSE");//
        sql.append("          nvl(hbrd.amount_firstup, 0)");//
        sql.append("       END AS amount_firstup");//
        sql.append("  FROM hrpbm_budgetreply hbr");//
        sql.append("  LEFT JOIN hrpbm_budgetreplydetail hbrd");//
        sql.append("    ON hbrd.pk_budgetreply = hbr.pk_budgetreply");//
        sql.append("  LEFT JOIN hrpbm_budgetdept hbd");//
        sql.append("    ON hbd.pk_budgetdept = hbrd.pk_budgetdept");//
        sql.append("  LEFT JOIN bd_inoutbusiclass ee");//
        sql.append("    ON ee.pk_inoutbusiclass = hbrd.pk_inoutclass");//
        sql.append("  LEFT JOIN bd_project project");//
        sql.append("    ON project.pk_project = hbrd.pk_project");//
        sql.append("  LEFT JOIN pm_eps projectclass");//
        sql.append("    ON projectclass.pk_eps = project.pk_eps");//
        sql.append("  LEFT JOIN bd_project project2");//
        sql.append("    ON project2.pk_project = project.pk_parentpro");//
        sql.append("  LEFT JOIN bd_fundsource bf");//
        sql.append("    ON bf.pk_fundsource = hbrd.pk_fundsource");//
        sql.append("  LEFT JOIN (SELECT DISTINCT kmdzb.factorvalue5 AS pk_inoutbusiclass,");//
        sql.append("                             szxm.code          AS szxmcode,");//
        sql.append("                             szxm.name          AS szxmname,");//
        sql.append("                             sfzj.code          AS sfzjcode,");//
        sql.append("                             sfzj.NAME          AS sfzjname");//
        sql.append("               FROM fip_docview_b kmdzb");//
        sql.append("               LEFT JOIN fip_docview kmdz");//
        sql.append("                 ON kmdz.pk_classview = kmdzb.pk_classview");//
        sql.append("               LEFT JOIN bd_inoutbusiclass szxm");//
        sql.append("                 ON kmdzb.factorvalue5 = szxm.pk_inoutbusiclass");//
        sql.append("               LEFT JOIN bd_defdoc bmjjfl");//
        sql.append("                 ON kmdzb.factorvalue1 = bmjjfl.pk_defdoc");//
        sql.append("               LEFT JOIN bd_defdoc sfzj");//
        sql.append("                 ON kmdzb.factorvalue3 = sfzj.pk_defdoc");//
        sql.append("               LEFT JOIN bd_defdoc kmlx");//
        sql.append("                 ON kmdzb.factorvalue6 = kmlx.pk_defdoc");//
        sql.append("               LEFT JOIN bd_accasoa bd_accasoa");//
        sql.append("                 ON kmdzb.desdocvalue = bd_accasoa.pk_accasoa");//
        sql.append("               LEFT JOIN bd_account bd_account");//
        sql.append("                 ON bd_accasoa.pk_account = bd_account.pk_account");//
        sql.append("              WHERE kmdz.VIEWCODE = 'YS001') fip_docview_b");//
        sql.append("    ON hbrd.pk_inoutclass = fip_docview_b.pk_inoutbusiclass");//
        sql.append(" WHERE (hbrd.pk_budgettype = 'YS02' OR hbrd.pk_budgettype = 'YS03')");//
        sql.append("   AND hbrd.nyear = '" + nyear + "'");

        if (StringUtils.isNotBlank(isfund)) {
            sql.append("   AND fip_docview_b.sfzjcode = '" + isfund + "'");
        }

        if (StringUtils.isNotBlank(pk_inoutclass)) {
            String pk_inoutclassInString = convertToInClause(pk_inoutclass);
            sql.append("   AND hbrd.pk_inoutclass in (" + pk_inoutclassInString + ") \n");
        }

        if (StringUtils.isNotBlank(pk_org) && !"GLOBLE00000000000000".equals(pk_org)) {
            sql.append("   AND hbrd.pk_org = '" + pk_org + "' \n");// 财务组织
        }

        if (StringUtils.isNotBlank(budgetdept)) {
            String pk_budgetdeptInString = convertToInClause(budgetdept);
            sql.append("   AND hbrd.pk_budgetdept  in (" + pk_budgetdeptInString + ") \n");// 预算科室
        }

        if (StringUtils.isNotBlank(f1project)) {
            String f1projectStr = convertToInClause(f1project);
            sql.append("   AND project.pk_project in (" + f1projectStr + ") \n");// 一级项目
        }

        if (StringUtils.isNotBlank(f2project)) {
            String f2projectStr = convertToInClause(f2project);
            sql.append("   AND project2.pk_project in (" + f2projectStr + ") \n");// 二级项目
        }

        sql.append(" ORDER BY inoutbusiclasscode;");


        List<Map<String, Object>> list = (ArrayList<Map<String, Object>>) getBaseDAO().executeQuery(sql.toString(), new MapListProcessor());

        // 统计来源合计
        List<Map<String, Object>> newList = initListByfundSource(list);

        return newList;
    }

    private Field[] initField() {
        Field[] FieldInfo = new Field[fields.length];
        for (int i = 0; i < fields.length; i++) {
            Field filed = new Field();
            filed.setCaption(fieldCaptions[i]);
            filed.setDbColumnType(Types.VARCHAR);
            if (i == 6 || i == 7 || i == 8 || i == 9 || i == 10 || i == 11 || i == 13) { // 5,7对应编制金额，批复金额，金额是否需要调整字段类型，根据情况定
                filed.setDbColumnType(Types.DECIMAL);
                filed.setPrecision(28);
                filed.setScale(2);
            }

            filed.setFldname(fields[i]);
//			if (i == 2 || i == 6 || i == 8) {// 视情况而定
//				filed.setPrecision(500);
//				filed.setDbColumnType(Types.VARCHAR);
//			}
            FieldInfo[i] = filed;
        }
        return FieldInfo;
    }

    /**
     * 初始化metadata
     *
     * @return
     */
    private MetaData initMetaData() {
        Field[] FieldInfo = initField();
        MetaData md = new MetaData();
        for (int i = 0; i < fields.length; i++) {
            md.addField(FieldInfo[i]);
        }
        return md;
    }

    public static DataSet buildDataSetobj(MetaData meta, List<Map<String, Object>> list, String[] fields) {
        if (ArrayUtils.isEmpty(fields)) {
            ExceptionUtils.wrappBusinessException("报表字段列不能为空，请检查！！！");
        }
        DataSet ds = null;
        if (null == list || list.size() == 0) {
            // 返回空数据集, 用于给语义模型加载空数据用
            Object[][] datas = new Object[1][fields.length];
            ds = new DataSet(meta, datas);
        } else {
            Object[][] datas = new Object[list.size()][fields.length];
            for (int i = 0; i < list.size(); i++) {
                for (int j = 0; j < fields.length; j++) {
                    datas[i][j] = list.get(i).get(fields[j].toString());
                    //vos[i].getAttributeValue(fields[j]);
                }
            }
            ds = new DataSet(meta, datas);
        }
        return ds;
    }

    public static String convertToInClause(String value) {
        if (StringUtils.isBlank(value)) {
            return "";
        }
        String[] values = value.split(",");

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < values.length; i++) {
            sb.append('\'').append(values[i]).append('\'');
            if (i < values.length - 1) {
                sb.append(',');
            }
        }
        return sb.toString();
    }

    public List<Map<String, Object>> initListByfundSource(List<Map<String, Object>> list) {

        if(CollectionUtils.isEmpty(list)){
            return new ArrayList<>();
        }

        Map<String,List<Map<String, Object>>> groupMap = new HashMap<>();
        for (int i = 0; i < list.size(); i++) {

            Map<String, Object> map = list.get(i);
            BigDecimal amount = new BigDecimal(0);

            /**
             * 封装来源款项
             */
            if(map.get("amount_firstup") instanceof BigDecimal){
                amount = (BigDecimal) map.get("amount_firstup");
            }else{
                Integer amountInt = (Integer) map.get("amount_firstup");
                amount = new BigDecimal(amountInt);
            }

            map.put("amount01", new BigDecimal(0));
            map.put("amount02", new BigDecimal(0));
            map.put("amount03", new BigDecimal(0));
            map.put("amount04", new BigDecimal(0));
            map.put("amount05", new BigDecimal(0));

            String sourcecode = (String) map.get("fundsourcecode");
            if(StringUtils.isNotBlank(sourcecode)){
                String sourcecodeKey = "amount" + sourcecode;
                map.put(sourcecodeKey, amount);
                map.put("amount", amount);
            }

            /**
             * 聚类数据分组
             */
            String pk_f1project = (String) map.get("pk_f1project");
            String pk_f2project = (String) map.get("pk_f2project");
            String type_name = (String) map.get("type_name");
            String inoutclassname = (String) map.get("inoutclassname");
            String key = pk_f1project + "-" + pk_f2project + "-" + type_name + "-" + inoutclassname;

            List<Map<String, Object>> mapList = null;
            if(groupMap.containsKey(key)){
                mapList = groupMap.get(key);
            }else{
                mapList = new ArrayList<>();
            }
            mapList.add(map);
            groupMap.put(key,mapList);
        }

        List<Map<String, Object>> returnList = new ArrayList<>();

        for (Entry<String, List<Map<String, Object>>> entry : groupMap.entrySet()) {
            List<Map<String, Object>> value = entry.getValue();

            BigDecimal fundsourceamount = new BigDecimal(0);
            BigDecimal amount_01 = new BigDecimal(0);
            BigDecimal amount_02 = new BigDecimal(0);
            BigDecimal amount_03 = new BigDecimal(0);
            BigDecimal amount_04 = new BigDecimal(0);
            BigDecimal amount_05 = new BigDecimal(0);
            BigDecimal amountTotal = new BigDecimal(0);

            Map<String, Object> baseMap = new HashMap<>();

            for (int i = 0; i < value.size(); i++) {
                Map<String, Object> map = value.get(i);
                BigDecimal amount01 = (BigDecimal) map.get("amount01");
                BigDecimal amount02 = (BigDecimal) map.get("amount02");
                BigDecimal amount03 = (BigDecimal) map.get("amount03");
                BigDecimal amount04 = (BigDecimal) map.get("amount04");
                BigDecimal amount05 = (BigDecimal) map.get("amount05");
                BigDecimal amount = (BigDecimal) map.get("amount");

                amount_01 = amount_01.add(amount01);
                amount_02 = amount_02.add(amount02);
                amount_03 = amount_03.add(amount03);
                amount_04 = amount_04.add(amount04);
                amount_05 = amount_05.add(amount05);
                amountTotal = amountTotal.add(amount);

                if(i==0){
                    baseMap = map;
                }
            }

            fundsourceamount = fundsourceamount.add(amount_01);
            fundsourceamount = fundsourceamount.add(amount_02);
            fundsourceamount = fundsourceamount.add(amount_03);
            fundsourceamount = fundsourceamount.add(amount_04);
            fundsourceamount = fundsourceamount.add(amount_05);

            baseMap.put("amount", amountTotal);
            baseMap.put("amount_01", amount_01);
            baseMap.put("amount_02", amount_02);
            baseMap.put("amount_03", amount_03);
            baseMap.put("amount_04", amount_04);
            baseMap.put("amount_05", amount_05);
            baseMap.put("fundsourceamount", fundsourceamount);

            returnList.add(baseMap);
        }

        return returnList;
    }

}
